home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / m2 / cat3src / cat / msglist.i < prev    next >
Text File  |  1997-10-26  |  62KB  |  1,775 lines

  1. IMPLEMENTATION MODULE msgList;
  2. (*$Z+*)
  3.  
  4. (*==============================================================*
  5.  * Modul:               CAT-Anzeigemodul fr Stichwortlisten    *
  6.  * Autor:               Dirk Steins                             *
  7.  * erstellt am:         25.07.1992                              *
  8.  * letzte Žnderung am:  27.10.1994                              *
  9.  * Version:             0.1                                     *
  10.  * Interne Version:     V#0001                                  *
  11.  *==============================================================*
  12.  
  13.  *----------------------------------------------------------------------------
  14.  * Datum    Vers. Autor  Žnderung (Arbeitsbericht)
  15.  *----------------------------------------------------------------------------
  16.  * 25.07.92 0.1   DS     Erste Implementation erstellt
  17.  * 27.07.92 0.2   DS     Erweiterungen um weitere Spalten in Anzeige und
  18.  *                       kleine Bugfixes
  19.  *----------------------------------------------------------------------------
  20.  *)
  21.  
  22. (*-- MM2-Module ------------------------------------------------------------*)
  23. FROM SYSTEM     IMPORT ADDRESS, ADR, TSIZE, CALLSYS, CADR;
  24. FROM Storage    IMPORT ALLOCATE, DEALLOCATE;
  25. IMPORT Lists;
  26. IMPORT GrafBase;
  27. IMPORT BinOps;
  28. IMPORT Strings;
  29. IMPORT StrConv;
  30. IMPORT MOSGlobals;
  31. IMPORT Keyboard;
  32. IMPORT Block;
  33. FROM Keyboard  IMPORT SpecialCode;
  34.  
  35. (*-- Cat-Module ------------------------------------------------------------*)
  36. FROM Void         IMPORT v;
  37. FROM UserInformation IMPORT UserBLK;
  38.  
  39. IMPORT data;
  40. IMPORT dataSys;
  41. IMPORT EditTypes;
  42. IMPORT MTE;
  43. IMPORT VDIStandards;
  44. IMPORT MausTauschrsc;
  45. IMPORT CatTypes;
  46. IMPORT handlePool;
  47. IMPORT ConfVars;
  48. IMPORT WdwManager;
  49. IMPORT RectFuncs;
  50. IMPORT FontSelect;
  51. IMPORT CatGlobal;
  52. IMPORT CatFiles;
  53. IMPORT grin;
  54. IMPORT grinTools;
  55. IMPORT Varnames;
  56. IMPORT QuickSort;
  57. IMPORT ZSearchDial;
  58. IMPORT GroupSelect;
  59. IMPORT Clip;
  60. IMPORT SearchHelp;
  61. IMPORT AssFuncs;
  62. IMPORT ConvertDate;
  63. IMPORT UUDecode;
  64. IMPORT Protokoll;
  65.  
  66. (*-- Magic-Lib -------------------------------------------------------------*)
  67. IMPORT MagicStrings;
  68. IMPORT MagicAES;
  69. IMPORT MagicVDI;
  70. IMPORT MagicFSM;
  71. IMPORT MagicDOS;
  72. IMPORT MagicConvert;
  73.  
  74. (*-- Magic-Tools -----------------------------------------------------------*)
  75. IMPORT mtAppl;
  76. IMPORT mtArea;
  77. IMPORT mtUtils;
  78. IMPORT mtAlerts;
  79. IMPORT mtDials;
  80. IMPORT mtPopups;
  81. IMPORT mtTextfiles;
  82. IMPORT mtXobjects;
  83.  
  84. FROM MsgListBase IMPORT
  85.     maxParts, partFormatLength, Selected, inTree, notRead, doRedraw, firstRead, initRead,
  86.     lEntry, listEntry , lineDist, pixOffset, privateParts , globalParts, 
  87.     ownEff, quoteEff, lastSaveMode , extendedCommentMode, butBox, selPop, 
  88.     removePop, sortPop, listEntryPtr, listArray, listArrayPtr, 
  89.     partNameType, partFormat, partType, partArrayType, partArrayDesc, 
  90.     listWindow, listWdwPtr, sortType, globalNumber, 
  91.     windows, FindNum, ClearNum, FindWinCond, FindHandleCond, 
  92.     FindGroupCond, findMsgIdx, FindNextSelected, FindPrevSelected, 
  93.     FindNextDeselected, FindPrevDeselected, listNextMess, 
  94.     hasSelectedEntries, countSelectedEntries, toggleBit, redrawEntry, 
  95.     toggleEntry, invertSelection, deselectEntries, deselectReadEntries, 
  96.     drawCursor, ShowCursor, AdjustTreePos, GetLinePart, shrinkToEnd, 
  97.     shrinkList, showAll, selectTree, selectFromTop, removeTree, 
  98.     listSelectFiltered, openSelected, freeList, doSort, doMark, 
  99.     redrawButton, careForSelected, drawListWdw, 
  100.     checkPopups, handleButtons, clickInListWindow, handleListTimer, 
  101.     handleListKey, getListScroll, closeListWindow, topListWdw, 
  102.     untopListWdw, updateListWdw, hideListWdw, setListWork, snapListWdw, 
  103.     listGetSelectedSize, listGetSelectedData, listGetHeader, 
  104.     listReadData, MakeTitle;
  105.  
  106.  
  107.   CONST     LF = 12C;
  108.             CR = 15C;
  109.     
  110.         
  111.                     
  112. (* ---------------------- Font-Funktionen ----------------------- *)
  113.  
  114. PROCEDURE iListSetFont (wdw : INTEGER; fnt, fntSize : INTEGER; redraw: BOOLEAN);
  115. (* Setzt den Font fr das Stichwortlistenfenster *)
  116.   VAR r : GrafBase.Rectangle;
  117.       ptr : listWdwPtr;
  118.       varName : CatTypes.String255;
  119. BEGIN
  120.   IF handlePool.FindEntry (ADR(wdw), FindWinCond, windows, ptr)
  121.   THEN
  122.     WITH ptr^ DO
  123.       font := fnt;
  124.       fontSize := fntSize;
  125.       FontSelect.SetFont (vdi, font, fontSize, TRUE, monoSpaced, isFSM, charWidth, charHeight);
  126.       maxWidth := partArray.width * charWidth;
  127.       (* Jetzt ist der Font gesetzt. Jetzt noch Window snappen und dann neu
  128.        * zeichnen lassen 
  129.        *)
  130.       Strings.Concat (cListFont, StrConv.IntToStr (number, 0), varName, v.bool);
  131.       v.bool := ConfVars.SetConfigInt (varName, font);
  132.       Strings.Concat (cListSize, StrConv.IntToStr (number, 0), varName, v.bool);
  133.       v.bool := ConfVars.SetConfigInt (varName, fontSize);
  134.       WdwManager.SetDocumentParms (wdw, 1, charHeight+lineDist);
  135.       WdwManager.GetWdwSize (wdw, r);
  136.       WdwManager.SetWdwSize (wdw, r);
  137.       r := listWork;
  138.       INC (r.x, pixOffset);
  139.       IF redraw THEN WdwManager.RedrawWdw (wdw, r); END;
  140.     END; (* WITH ed^ DO *)
  141.   END;
  142. END iListSetFont;
  143.  
  144. (*-------------- exportierte Funktionen -----------------------*)
  145.  
  146. PROCEDURE listRemoveTree (hdl: LONGCARD; grinWdw: INTEGER; 
  147.                           msgNum : CARDINAL; setReadFlag: BOOLEAN);
  148. (* Entfernt den Baum mit der Nachricht msgNum aus der Liste im Fenster 
  149.  * wdw, falls das grinWdw bereinstimmt
  150.  *)
  151.  
  152. VAR ptr: listWdwPtr;
  153.     idx: CARDINAL;
  154.  
  155.   (*$H+*)
  156.   PROCEDURE unselTree (handle: data.OneGroupHandle; 
  157.                        msgIdx: CARDINAL;
  158.                        mess  : dataSys.pBlockPtr);
  159.     VAR i : CARDINAL;
  160.   BEGIN
  161.     (* search for mess *)
  162.     WITH ptr^ DO
  163.       IF setReadFlag
  164.       THEN
  165.         INCL (mess^.bits, dataSys.bGelesen);
  166.         data.SetBits (handle, msgIdx, mess^.bits);
  167.       END;
  168.       (* First try normal list *)
  169.       IF (msgIdx <= maxPos) & (list^[msgIdx].msgNum = msgIdx)
  170.       THEN
  171.         i := msgIdx;
  172.       ELSE
  173.         (* Not found, search from end *)
  174.         i := maxPos;
  175.         WHILE (list^[i].msgNum # msgIdx) & (i > 0) DO DEC (i) END;
  176.       END;
  177.       IF list^[i].msgNum = msgIdx 
  178.       THEN
  179.         EXCL (list^[i].flags, Selected);
  180.         EXCL (list^[i].flags, inTree);
  181.       END;
  182.     END;
  183.   END unselTree;
  184.  
  185. BEGIN
  186.   IF handlePool.FindEntry(ADR(hdl), FindHandleCond, windows, ptr) 
  187.   THEN
  188.     IF grinWdw # ptr^.grinWindow
  189.     THEN
  190.       RETURN
  191.     END;
  192.     WITH ptr^ DO
  193.       findMsgIdx (ptr, msgNum, idx);
  194.       IF idx < dataSys.notSaved
  195.       THEN
  196.         (* Erstmal Baum deselektieren *)
  197.         data.WalkTree (grHandle^.Zugriff, msgNum, TRUE, unselTree);
  198.         (* Die aktuelle darf nicht entfernt werden, da sonst 
  199.          * listNextMess nicht funktioniert
  200.          *)
  201.         INCL (list^[idx].flags, Selected);
  202.         (* Und jetzt Liste verkleinern *)
  203.         IF ~shrinkList (ptr, FALSE, TRUE)
  204.         THEN
  205.           WdwManager.FullRedrawWdw (wdw);
  206.         END;
  207.       END;
  208.     END;
  209.   END;
  210. END listRemoveTree;
  211.  
  212. PROCEDURE listChangeFlags (hdl: LONGCARD; grinWdw: INTEGER; 
  213.                            msgNum: CARDINAL; newBits: BITSET);
  214. (* grin teilt der Stichwortliste mit, daž sich bei einer Nachricht
  215.  * die Flags ge„ndert haben 
  216.  *)
  217. VAR ptr: listWdwPtr;
  218.     idx: CARDINAL;
  219. BEGIN
  220.   IF handlePool.FindEntry(ADR(hdl), FindHandleCond, windows, ptr) 
  221.   THEN
  222.     IF grinWdw # ptr^.grinWindow
  223.     THEN
  224.       RETURN 
  225.     END;
  226.     WITH ptr^ DO
  227.       findMsgIdx (ptr, msgNum, idx);
  228.       IF idx < dataSys.notSaved
  229.       THEN
  230.         IF dataSys.bGelesen IN newBits
  231.         THEN
  232.           EXCL (list^[idx].flags, notRead);
  233.         ELSE
  234.           INCL (list^[idx].flags, notRead);
  235.         END;
  236.         (* Eintrag muž komplett neu gezeichnet werden *)
  237.         INCL (list^[idx].flags, doRedraw);
  238.       END;
  239.     END;
  240.   END;
  241. END listChangeFlags;
  242.  
  243.  
  244. (*$H+*)
  245. PROCEDURE listOpenWithProc (gruppe : CARDINAL;  whichNr : getNumberProc; grinWdw : INTEGER; mode: grin.openMode);
  246. (* Ein Stichwortlistenfenster wird ge”ffnet *)
  247.   VAR ptr       : listWdwPtr;
  248.       handlePtr : handlePool.oneHandlePtr;
  249.       varName   : ARRAY[0..39] OF CHAR;
  250.       work      : GrafBase.Rectangle;
  251.       comps     : BITSET;
  252.       i         : CARDINAL;
  253.       which     : CARDINAL;
  254.       openNew   : BOOLEAN;
  255.       num       : INTEGER;
  256.       saveVar   : SearchHelp.SearchRecordType;
  257.       doRedraw  : BOOLEAN;
  258. BEGIN
  259.   IF handlePool.FindEntry (ADR (gruppe), FindGroupCond, windows, ptr)
  260.   THEN 
  261.     IF ptr^.wdw >= 0
  262.     THEN
  263.       (* Gruppe schon als Stichwortfenster offen *)
  264.       WdwManager.TopWindow (ptr^.wdw);
  265.       openNew := FALSE;
  266.     ELSE
  267.       openNew := TRUE;
  268.     END;
  269.   ELSE 
  270.     ptr := NIL;
  271.     openNew := FALSE;
  272.   END;
  273.   IF (ptr = NIL) OR openNew
  274.   THEN
  275.     (* Gruppe ”ffnen und Stichwortliste anzeigen *)
  276.     IF ((ptr = NIL) & handlePool.BlankToList(ptr, TSIZE(listWindow), windows)) OR openNew THEN
  277.       IF openNew OR (~openNew & handlePool.GetOneDatahandle(gruppe, handlePtr)) THEN
  278.         IF openNew
  279.         THEN
  280.           handlePtr := ptr^.grHandle;
  281.         END;
  282.         ptr^.wdw := -1;
  283.         which := whichNr (handlePtr^.Zugriff);
  284.         ptr^.grHandle := handlePtr;
  285.         ptr^.grinWindow := grinWdw;
  286.         (* Fensternummer dieses Moduls herausfinden *)
  287.         ptr^.number := FindNum ();
  288.         Strings.Concat (cListWdw, StrConv.IntToStr (ptr^.number, 0), varName,
  289.                         v.bool);
  290.         IF ~ConfVars.GetConfigRect (varName, ptr^.listWork) 
  291.         THEN
  292.           IF (ptr^.number > 0)
  293.           THEN
  294.             num := ptr^.number - 1;
  295.             Strings.Concat (cListWdw, StrConv.IntToStr (num, 0), varName,
  296.                             v.bool);
  297.           END;
  298.           ConfVars.GetConfDefRect (varName, ptr^.listWork, EditTypes.deskSize);
  299.           IF ~ RectFuncs.RectEqual (ptr^.listWork, EditTypes.deskSize)
  300.           THEN
  301.             INC (ptr^.listWork.x, 2*mtAppl.CharWidth);
  302.             INC (ptr^.listWork.y, mtAppl.CharHeight);
  303.           END;
  304.           Strings.Concat (cListWdw, StrConv.IntToStr (ptr^.number, 0), varName, v.bool);
  305.           v.bool := ConfVars.SetConfigRect (varName, ptr^.listWork);
  306.         END;
  307.         ConfVars.GetConfDefInt (cListLeftOffset, pixOffset, pixOffset);
  308.         pixOffset := BinOps.HigherInt (0, pixOffset);
  309.         ConfVars.GetConfDefInt (cListLineDist, lineDist, lineDist);
  310.         lineDist := BinOps.HigherInt (0, lineDist);
  311.         (* Fensterkomponenten setzen *)
  312.         comps := {MagicAES.NAME..MagicAES.HSLIDE};
  313.         (* Infozeile brauchen wir nicht *)
  314.         EXCL (comps, MagicAES.INFO);
  315.  
  316.         IF ~openNew
  317.         THEN
  318.           MakeTitle (gruppe, ptr^.grName);
  319.           ptr^.maxPos   := data.LastMsgOfGroup (gruppe);
  320.           IF ptr^.maxPos = dataSys.empty
  321.           THEN
  322.             handlePool.FreeOneDataHandle(handlePtr);
  323.             handlePool.FreeOnePtr (ptr, windows);
  324.             ClearNum (ptr^.number);
  325.             RETURN
  326.           END;
  327.           IF which > ptr^.maxPos THEN which := ptr^.maxPos END;
  328.           ptr^.usedByGrin := 0;
  329.           (* Jetzt "Liste" aufbauen *)
  330.           ALLOCATE (ptr^.wholeList, LONG(ptr^.maxPos + 1) * LONG(TSIZE (listEntry)));
  331.           ptr^.list := ptr^.wholeList;
  332.         END;
  333.         IF ptr^.wholeList # NIL THEN
  334.           IF ~openNew
  335.           THEN
  336.             (* Liste fllen *)
  337.             FOR i := 0 TO ptr^.maxPos DO
  338.               ptr^.wholeList^[i] := listEntry(lEntry{i, {}, NIL});
  339.             END;
  340.           END;
  341.           ptr^.charHeight  := 1;
  342.           ptr^.charWidth   := 8;
  343.           ptr^.font := -1;
  344.           ptr^.fontSize := 10;
  345.           IF gruppe = dataSys.private
  346.           THEN
  347.             ptr^.partArray := privateParts;
  348.           ELSE
  349.             ptr^.partArray := globalParts;
  350.           END;
  351.           (* Fenster ”ffnen *)
  352.           IF WdwManager.OpenWindow (clickInListWindow, handleListKey, handleListTimer, 
  353.                                     EditTypes.deskSize, ptr^.listWork, comps, TRUE, 
  354.                                     '', ptr^.grName, snapListWdw, closeListWindow, 
  355.                                     drawListWdw, topListWdw, untopListWdw, updateListWdw,
  356.                                     setListWork, getListScroll, hideListWdw, 
  357.                                     pixOffset, ptr, FALSE, TRUE, TRUE, TRUE, 
  358.                                     ptr^.wdw, ptr^.vdi)
  359.           THEN
  360.             WITH ptr^ DO
  361.               (* Als DDServer installieren *)
  362.               WdwManager.WdwInstallDDServer (wdw, listGetHeader, listReadData);
  363.               isHidden := FALSE;
  364.               (* grin Bescheid sagen *)
  365.               v.bool := grin.grinSetListWdw (grinWindow, grin.grinNextMess, LONGCARD(ptr));
  366.               (* Kein Cursor am Anfang *)
  367.               cursPos := -1;
  368.               (* Font aus Configvariablen lesen und setzen *)
  369.               Strings.Concat (cListFont, StrConv.IntToStr (number, 0), varName,   v.bool);
  370.               IF ~ConfVars.GetConfigInt (varName, font)
  371.               THEN
  372.                 num := BinOps.HigherInt (number-1, 0);
  373.                 Strings.Concat (cListFont, StrConv.IntToStr (num, 0), varName,   v.bool);
  374.                 ConfVars.GetConfDefInt (varName, font, 1);
  375.                 Strings.Concat (cListSize, StrConv.IntToStr (num, 0), varName,
  376.                                 v.bool);
  377.                 ConfVars.GetConfDefInt (varName, fontSize, 10);
  378.                 
  379.                 Strings.Concat (cListFont, StrConv.IntToStr (number, 0), varName, v.bool);
  380.                 v.bool := ConfVars.SetConfigInt (varName, font);
  381.                 Strings.Concat (cListSize, StrConv.IntToStr (number, 0), varName, v.bool);
  382.                 v.bool := ConfVars.SetConfigInt (varName, fontSize);
  383.               ELSE
  384.                 Strings.Concat (cListSize, StrConv.IntToStr (number, 0), varName, v.bool);
  385.                 ConfVars.GetConfDefInt (varName, fontSize, 10);
  386.               END;
  387.               findMsgIdx (ptr, which, startPos);
  388.               leftOffset := 0;
  389.               maxWidth   := 0;
  390.  
  391.               (* Modus merken *)
  392.               unreadOrNew := (mode=grin.mFirstNew) OR (mode=grin.mUnread);
  393.               openMode := mode;
  394.               isLocked := FALSE;
  395.               doRedraw := FALSE;
  396.               (* Jetzt eventuell Liste verkleinern *)
  397.               ConfVars.GetConfDefBool (cListShrink, v.bool, FALSE);
  398.               IF unreadOrNew & v.bool
  399.               THEN
  400.                 (* Liste verkleinern *)
  401.                 shrinkToEnd (ptr, FALSE);
  402.                 (* doRedraw := TRUE; *)
  403.               END;
  404.               (* Jetzt eventuell gefilterte rausnehmen *)
  405.               ConfVars.GetConfDefBool (cListFilter, v.bool, FALSE);
  406.               IF unreadOrNew & v.bool
  407.               THEN
  408.                 (* Gefilterte selektieren und dann Liste verkleinern *)
  409.                 listSelectFiltered (ptr^.wdw, TRUE, FALSE);
  410.                 v.bool := shrinkList (ptr, TRUE, FALSE);
  411.                 (* doRedraw := TRUE; *)
  412.               END;
  413.  
  414.               (* Jetzt mal nachsehen, ob wir auch sortieren mssen *)
  415.               ConfVars.GetConfDefInt (cListSort, v.int, 3);
  416.               IF unreadOrNew & (sortType(v.int) # sNum)
  417.               THEN
  418.                 isLocked := TRUE;
  419.                 doSort (ptr, sortType(v.int), FALSE);
  420.                 doRedraw := TRUE;
  421.                 isLocked := FALSE;
  422.               END;
  423.               IF unreadOrNew 
  424.               THEN
  425.                 saveVar := SearchHelp.suchVar;
  426.                 FOR i := 1 TO 10 DO
  427.                   MagicStrings.Assign (cListSearch, varName);
  428.                   MagicStrings.Append (StrConv.CardToStr (i, 0), varName);
  429.                   ConfVars.GetConfDefBool (varName, v.bool, FALSE);
  430.                   IF v.bool
  431.                   THEN
  432.                     isLocked := TRUE;
  433.                     (* Ok, steht auf TRUE, also selektieren *)
  434.                     IF SearchHelp.getKonf (i-1, SearchHelp.suchVar)
  435.                      & SearchHelp.ValidateKonf (SearchHelp.suchVar)
  436.                     THEN
  437.                       doMark (ptr, FALSE);
  438.                       doRedraw := TRUE;
  439.                     END;
  440.                     isLocked := FALSE;
  441.                   END;
  442.                 END;
  443.                 SearchHelp.suchVar := saveVar;
  444.               END;
  445.  
  446.               (* Noch ein bižchen was fr die Window-Library *)
  447.               WdwManager.SetNewDocument (wdw, GrafBase.LongRect{LONG(leftOffset), startPos, LONG(maxWidth), maxPos}, FALSE);
  448.               (* Fonts laden *)
  449.               FontSelect.LoadFonts (vdi, v.int);
  450.               (* Font setzen *)
  451.               iListSetFont (wdw, font, fontSize, FALSE);
  452.               (* Jetzt noch ein paar andere VDI-Variablen setzen *)
  453.               v.int := MagicVDI.SetFillstyle (vdi, MagicVDI.Full);
  454.               v.int := MagicVDI.SetFillinterior (vdi, MagicVDI.Full);
  455.               v.int := MagicVDI.SetFillcolor (vdi, CatGlobal.listBackCol);
  456.               (* Schreibmodus setzen *)
  457.               v.int := MagicVDI.SetWritemode (vdi, MagicVDI.REPLACE);
  458.  
  459.  
  460.               IF doRedraw
  461.               THEN
  462.                 WdwManager.FullRedrawWdw (ptr^.wdw);
  463.               END;
  464.             END;
  465.           ELSE
  466.             handlePool.FreeOneDataHandle(handlePtr);
  467.             handlePool.FreeOnePtr (ptr, windows);
  468.             ClearNum (ptr^.number);
  469.             MTE.info ("CAT:|Es ist kein Fenster oder|keine VDI-Workstation fr|die Stichwortliste mehr frei.][[Abbruch]");          END;
  470.         ELSE
  471.           handlePool.FreeOneDataHandle(handlePtr);
  472.           handlePool.FreeOnePtr (ptr, windows);
  473.           ClearNum (ptr^.number);
  474.           MTE.noMemAlert();
  475.         END;
  476.       ELSE
  477.         handlePool.FreeOnePtr (ptr, windows);
  478.         MTE.noMemAlert();
  479.       END;
  480.     ELSE
  481.       MTE.noMemAlert();
  482.     END;
  483.   END;
  484. END listOpenWithProc;
  485.  
  486. PROCEDURE listOpen (gruppe, which : CARDINAL; grinWindow : INTEGER; mode: grin.openMode);
  487. (* Ein Stichwortlistenfenster wird ge”ffnet,
  488.  * die Nummer wird ber eine Prozedur ermittelt
  489.  *)
  490.   PROCEDURE Standard(ptr : data.OneGroupHandle):CARDINAL;
  491.   BEGIN
  492.     RETURN which
  493.   END Standard;
  494. BEGIN
  495.   listOpenWithProc(gruppe, Standard, grinWindow, mode);
  496. END listOpen;
  497. (*$H=*)
  498.  
  499. PROCEDURE listClose (wdw : INTEGER);
  500. (* Ein Stichwortlistenfenster wird geschlossen *)
  501.   VAR p : listWdwPtr;
  502. BEGIN
  503.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  504.     v.bool := WdwManager.CloseWindow (wdw, TRUE);
  505.   END;
  506. END listClose;
  507.  
  508. PROCEDURE listSelectAll(wdw : INTEGER; withRedraw: BOOLEAN);
  509. (* Alle Nachrichten in dem Fenster werden selektiert *)
  510.   VAR p : listWdwPtr;
  511.       i : CARDINAL;
  512. BEGIN
  513.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  514.     WITH p^ DO
  515.       CatGlobal.busyMouse();
  516.       FOR i := 0 TO maxPos DO
  517.         INCL (list^[i].flags, Selected);
  518.         IF (i MOD 75 = 0) THEN
  519.           CatGlobal.busyMouse();
  520.         END;
  521.       END;
  522.       mtAppl.MouseArrow();
  523.     END;
  524.     (* Und jetzt vorsichtshalber Redraw ausl”sen *)
  525.     IF withRedraw
  526.     THEN 
  527.       WdwManager.FullRedrawWdw (wdw);
  528.     END; 
  529.   END;
  530. END listSelectAll;
  531.  
  532. PROCEDURE listSelectNew(wdw : INTEGER);
  533. (* Alle Nachrichten in dem Fenster werden selektiert *)
  534.   VAR p : listWdwPtr;
  535.       start,
  536.       i : CARDINAL;
  537. BEGIN
  538.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  539.     WITH p^ DO
  540.       CatGlobal.busyMouse();
  541.       start := data.FirstNewMsg(grHandle^.group);
  542.       (* Jetzt die erste Message finden, deren Nummer > start ist *)
  543.       FOR i := 0 TO maxPos DO
  544.         IF (list^[i].msgNum >= start)
  545.         THEN
  546.           INCL (list^[i].flags, Selected);
  547.           IF (i MOD 75 = 0) THEN
  548.             CatGlobal.busyMouse();
  549.           END;
  550.         END;
  551.       END;
  552.       mtAppl.MouseArrow();
  553.     END;
  554.     (* Und jetzt vorsichtshalber Redraw ausl”sen *)
  555.     WdwManager.FullRedrawWdw (wdw);
  556.   END;
  557. END listSelectNew;
  558.  
  559. (*-- Ausgabefunktionen -------------------------------------------------*)
  560.  
  561. CONST   smListe     = 1;
  562.         smOutfile   = 2;
  563.         smText      = 3;
  564.         smData      = 4;
  565.         smDecode    = 5;
  566.         smStatus    = 6;
  567.  
  568. PROCEDURE listSaveStatus (ptr: listWdwPtr; f: mtTextfiles.TEXTFILE);
  569.   VAR firstSel,
  570.       msgNum    : CARDINAL;
  571.       idx       : CARDINAL;
  572.       mess      : data.MessageType;
  573.       line      : CatTypes.String255;
  574.       status    : CatTypes.String255;
  575.       j         : INTEGER;
  576. BEGIN
  577.   WITH ptr^ DO
  578.     IF hasSelectedEntries (ptr, firstSel)
  579.     THEN
  580.       msgNum := list^[firstSel].msgNum;
  581.       idx := firstSel;
  582.       WHILE msgNum < dataSys.notSaved DO
  583.         (* Header der Message lesen *)
  584.         data.ReadHeader (grHandle^.Zugriff, msgNum, mess);
  585.         IF data.error = data.noError
  586.         THEN
  587.           (* MsgId ausgeben *)
  588.           mtTextfiles.WriteLine (f, "#");
  589.           mtTextfiles.WriteLine (f, mess.MailID^);
  590.           mtTextfiles.WriteLn (f);
  591.           (* Status ausgeben *)
  592.           mtTextfiles.WriteLine (f, "BG");
  593.           mtTextfiles.WriteLn (f);
  594.           IF mess.InfoStrings # NIL THEN 
  595.             DEALLOCATE (mess.InfoStrings, 0);
  596.           END;
  597.         END;
  598.         (* N„chste selektierte finden *)
  599.         INC (idx);
  600.         WHILE (idx <= maxPos) & ~(Selected IN list^[idx].flags) DO INC (idx) END;
  601.         IF idx <= maxPos
  602.         THEN
  603.           msgNum := list^[idx].msgNum;
  604.         ELSE
  605.           msgNum := dataSys.empty;
  606.         END;
  607.       END;
  608.     END;
  609.   END;
  610. END listSaveStatus;
  611.  
  612. PROCEDURE listSaveList (ptr: listWdwPtr; f: mtTextfiles.TEXTFILE);
  613.   VAR firstSel,
  614.       msgNum    : CARDINAL;
  615.       idx       : CARDINAL;
  616.       mess      : data.MessageType;
  617.       line      : CatTypes.String255;
  618.       width     : INTEGER;
  619.       j         : INTEGER;
  620. BEGIN
  621.   WITH ptr^ DO
  622.     IF hasSelectedEntries (ptr, firstSel)
  623.     THEN
  624.       msgNum := list^[firstSel].msgNum;
  625.       idx := firstSel;
  626.       WHILE msgNum < dataSys.notSaved DO
  627.         (* Header der Message lesen *)
  628.         data.ReadHeader (grHandle^.Zugriff, msgNum, mess);
  629.         IF data.error # data.noError
  630.         THEN
  631.           WITH mess DO
  632.             MailID := NIL;
  633.             Betreff := NIL;
  634.             Absender := NIL;
  635.             Empfaenger := NIL;
  636.             mid := NIL;
  637.             rid := NIL;
  638.             box := NIL;
  639.             name := NIL;
  640.             mime := NIL;
  641.             gate := NIL;
  642.             followupTo := NIL;
  643.             replyTo := NIL;
  644.             gate := NIL;
  645.             InfoStrings := NIL;
  646.           END;
  647.         END;
  648.         (* Zeile ausgeben *)
  649.         FOR j := 0 TO partArray.lines-1 DO
  650.           GetLinePart (ptr, msgNum, mess, line, partArray.parts[j]);
  651.           width := partArray.parts[j].w;
  652.           mtTextfiles.WriteLine (f, line);
  653.           mtTextfiles.WriteLine (f, Strings.Space (width - INTEGER(LENGTH (line))));
  654.           mtTextfiles.WriteChar (f, ' ');
  655.         END;
  656.         mtTextfiles.WriteLn (f);
  657.         IF mess.InfoStrings # NIL THEN 
  658.           DEALLOCATE (mess.InfoStrings, 0);
  659.         END;
  660.         (* N„chste selektierte finden *)
  661.         INC (idx);
  662.         WHILE (idx <= maxPos) & ~(Selected IN list^[idx].flags) DO INC (idx) END;
  663.         IF idx <= maxPos
  664.         THEN
  665.           msgNum := list^[idx].msgNum;
  666.         ELSE
  667.           msgNum := dataSys.empty;
  668.         END;
  669.       END;
  670.     END;
  671.   END;
  672. END listSaveList;
  673.  
  674. PROCEDURE LineOut (file : mtTextfiles.TEXTFILE; ch : ARRAY OF CHAR; str : CatTypes.Str255Ptr);
  675. BEGIN
  676.   IF str = NIL THEN RETURN END;
  677.   IF str^[0] = 0C THEN RETURN END;
  678.   IF ch[0] # 0C THEN mtTextfiles.WriteLine (file, ch); END;
  679.   mtTextfiles.WriteLine (file, str^);
  680.   mtTextfiles.WriteLn (file);
  681. END LineOut;
  682.  
  683. PROCEDURE buildDate (date: LONGCARD; VAR str : ARRAY OF CHAR);
  684. BEGIN
  685.   MagicStrings.Assign (StrConv.LNumToStr (date, 10, 9, '0'), str);
  686.   Strings.Insert ('199', 0, str, v.bool);
  687. END buildDate;
  688.  
  689. PROCEDURE buildFlagLine (flags: BITSET; VAR str : ARRAY OF CHAR);
  690.   VAR i : INTEGER;
  691.   (* zur Definition der eigenen Flagzeile verweise ich auf 
  692.    * parser.CheckFlagLine
  693.    *)
  694. BEGIN
  695.   i := 0;
  696.   IF dataSys.bGelesen IN flags          THEN str[i] := 'G'; INC (i); END;
  697.   IF dataSys.bTotalloeschung IN flags   THEN str[i] := 'X'; INC (i); END;
  698.   IF dataSys.bInteressant IN flags      THEN str[i] := 'F'; INC (i); END;
  699.   IF dataSys.bFiltered IN flags         THEN str[i] := 'L'; INC (i); END;
  700.   IF dataSys.bTeilloeschung IN flags    THEN str[i] := 'D'; INC (i); END;
  701.   IF dataSys.bKommentieren IN flags     THEN str[i] := 'K'; INC (i); END;
  702.   IF dataSys.bAntworten   IN flags      THEN str[i] := 'B'; INC (i); END;
  703.   IF dataSys.bVererben    IN flags      THEN str[i] := 'V'; INC (i); END;
  704.   IF dataSys.bUser1       IN flags      THEN str[i] := 'C'; INC (i); END;
  705.   IF dataSys.bUser2       IN flags      THEN str[i] := 'M'; INC (i); END;
  706.   str[i] := 0C;
  707. END buildFlagLine;
  708.  
  709. PROCEDURE messageOut (f: mtTextfiles.TEXTFILE; mess: data.MessageType; REF pre: ARRAY OF CHAR);
  710.   VAR idx       : CARDINAL;
  711.       lfDone    : BOOLEAN;
  712.       ch        : CHAR;
  713. BEGIN
  714.   WITH mess DO
  715.     IF Text = NIL THEN RETURN END;
  716.     (* Und jetzt k”nnen wir den Text ausgeben *)
  717.     idx := 0;
  718.     lfDone := TRUE;
  719.     WHILE idx < textLen DO
  720.       ch := Text^[idx];
  721.       IF ch # LF
  722.       THEN
  723.         IF lfDone THEN mtTextfiles.WriteLine (f, pre); lfDone := FALSE; END;
  724.         mtTextfiles.WriteChar (f, ch);
  725.       ELSE
  726.         IF lfDone THEN mtTextfiles.WriteLine (f, pre); END;
  727.         mtTextfiles.WriteLn (f);
  728.         lfDone := TRUE;
  729.       END;
  730.       INC (idx);
  731.     END;
  732.     IF ~lfDone THEN mtTextfiles.WriteLn (f); END;
  733.   END;
  734. END messageOut;
  735.  
  736. PROCEDURE listSaveOutfile (ptr: listWdwPtr; f: mtTextfiles.TEXTFILE; append: BOOLEAN);
  737.   VAR firstSel  : CARDINAL;
  738.       msgNum    : CARDINAL;
  739.       idx       : CARDINAL;
  740.       groupName : CatTypes.String255;
  741.       dateLine  : CatTypes.String127;
  742.       mess      : data.MessageType;
  743.       fPos      : LONGCARD;
  744. BEGIN
  745.   WITH ptr^ DO
  746.     IF hasSelectedEntries (ptr, firstSel)
  747.     THEN
  748.       IF append
  749.       THEN
  750.         (* #CRLF am Dateiende entfernen *)
  751.         fPos := mtTextfiles.Textpos (f);
  752.         (* Ein Test ist hier nicht n”tig, append wird nur
  753.          * gesetzt, wenn es m”glich ist 
  754.          *)
  755.         mtTextfiles.SetTextpos (f, fPos-3);
  756.       END;
  757.       (* Gruppennamen rausfinden *)
  758.       IF grHandle^.group = dataSys.private
  759.       THEN
  760.         MagicStrings.Assign ('', groupName);
  761.       ELSE
  762.         GroupSelect.GroupName (grHandle^.group, groupName);
  763.       END;
  764.       msgNum := list^[firstSel].msgNum;
  765.       idx := firstSel;
  766.       WHILE msgNum < dataSys.notSaved DO
  767.         (* Message lesen *)
  768.         data.ReadMessage (grHandle^.Zugriff, msgNum, mess);
  769.         IF data.error = data.noError
  770.         THEN
  771.           WITH mess DO
  772.             (* Header ausgeben *)
  773.             LineOut (f, '#', MailID);
  774.             IF (grHandle^.group = dataSys.private) & (mess.EigeneNachricht)
  775.              & ((Absender = NIL) OR (Absender^[0] = 0C))
  776.             THEN
  777.               LineOut (f, 'V', ADR(CatGlobal.userName));
  778.             ELSE
  779.               LineOut (f, 'V', Absender);
  780.             END;
  781.             LineOut (f, 'W', Betreff);
  782.             LineOut (f, 'A', Empfaenger);
  783.             LineOut (f, 'G', ADR(groupName));
  784.             (* Datum noch holen *)
  785.             buildDate (tauschDate, dateLine);
  786.             LineOut (f, 'E', ADR (dateLine));
  787.             LineOut (f, '-', ADR (KommentierteID));
  788.             (* Jetzt noch den Usenet-Krempel *)
  789.             LineOut (f, 'N', name);
  790.             LineOut (f, 'I', mid);
  791.             LineOut (f, 'R', rid);
  792.             LineOut (f, 'O', box);
  793.             LineOut (f, 'M', mime);
  794.             LineOut (f, 'F', followupTo);
  795.             LineOut (f, 'T', replyTo);
  796.             LineOut (f, 'Y', gate);
  797.             (* Distribution rauspusten *)
  798.             IF distribution # data.dNone
  799.             THEN
  800.               dateLine [0] := CHR(ORD(distribution) + ORD('K'));
  801.               dateLine [1] := 0C;
  802.               LineOut (f, 'D', ADR(dateLine));
  803.             END;
  804.             (* Bei der pers”nlichen Gruppe muž eine Statuszeile ausgegeben werden
  805.              *)
  806.             IF grHandle^.group = dataSys.private
  807.             THEN
  808.               buildDate (statusDate, dateLine);
  809.               MagicStrings.Insert (Status, dateLine, 0);
  810.               LineOut (f, 'B', ADR(dateLine));
  811.             END;
  812.             (* Jetzt noch die Statuszeile *)
  813.             buildFlagLine (StatusBits, dateLine);
  814.             LineOut (f, 's', ADR(dateLine));
  815.             (* Und jetzt k”nnen wir den Text ausgeben *)
  816.             messageOut (f, mess, ':');
  817.             (* Speicher freigeben *)
  818.             DEALLOCATE (Text, 0);
  819.             DEALLOCATE (InfoStrings, 0);
  820.           END; (* WITH mess DO *)
  821.         END; (* IF data.error *)
  822.         (* N„chste selektierte finden *)
  823.         INC (idx);
  824.         WHILE (idx <= maxPos) & ~(Selected IN list^[idx].flags) DO INC (idx) END;
  825.         IF idx <= maxPos
  826.         THEN
  827.           msgNum := list^[idx].msgNum;
  828.         ELSE
  829.           msgNum := dataSys.empty;
  830.         END;
  831.       END; (* WHILE *)
  832.       (* Jetzt noch das Logfile schreiben *)
  833.       mtTextfiles.WriteLine (f, '#LOG');
  834.       mtTextfiles.WriteLn (f);
  835.       LineOut (f, ':!V', CADR(CatTypes.CatDate));
  836.       MagicStrings.Assign ('CAT ', dateLine);
  837.       MagicStrings.Append (CatTypes.CatVersion, dateLine);
  838.       LineOut (f, ':!', ADR(dateLine));
  839.       MagicStrings.Assign ('Database von ', dateLine);
  840.       MagicStrings.Append (CatGlobal.userName, dateLine);
  841.       LineOut (f, ':!', ADR(dateLine));
  842.       mtTextfiles.WriteLine (f, '#');
  843.       mtTextfiles.WriteLn (f);
  844.     END; (* IF hasSelectedEntries *)
  845.   END; (* WITH ptr^ DO *)
  846. END listSaveOutfile;
  847.  
  848. PROCEDURE listSaveText (ptr: listWdwPtr; f: mtTextfiles.TEXTFILE; dataMode: BOOLEAN);
  849.   VAR firstSel  : CARDINAL;
  850.       msgNum    : CARDINAL;
  851.       idx       : CARDINAL;
  852.       groupName : CatTypes.String255;
  853.       tmpLine   : CatTypes.String255;
  854.       mess      : data.MessageType;
  855.       i         : INTEGER;
  856.       emptyLines: INTEGER;
  857. BEGIN
  858.   WITH ptr^ DO
  859.     IF hasSelectedEntries (ptr, firstSel)
  860.     THEN
  861.       ConfVars.GetConfDefInt (cPrtLines, emptyLines, 1);
  862.       (* Gruppennamen rausfinden *)
  863.       GroupSelect.GroupName (grHandle^.group, groupName);
  864.       msgNum := list^[firstSel].msgNum;
  865.       idx := firstSel;
  866.       WHILE msgNum < dataSys.notSaved DO
  867.         (* Message lesen *)
  868.         data.ReadMessage (grHandle^.Zugriff, msgNum, mess);
  869.         IF data.error = data.noError
  870.         THEN
  871.           WITH mess DO
  872.             IF ~dataMode
  873.             THEN
  874.               (* Header ausgeben *)
  875.               LineOut (f, 'ID  : ', MailID);
  876.               LineOut (f, 'Gruppe: ', ADR(groupName));
  877.               LineOut (f, 'Followup-To: ', followupTo);
  878.               LineOut (f, 'Kommentar zu ', ADR (KommentierteID));
  879.               IF Absender # NIL
  880.               THEN
  881.                 MagicStrings.Assign (Absender^, tmpLine);
  882.                 MagicStrings.Append(' (', tmpLine);
  883.                 MagicStrings.Append(Datum, tmpLine);
  884.                 MagicStrings.Append(')', tmpLine);
  885.                 LineOut (f, 'Von : ', ADR(tmpLine));
  886.               END;
  887.               LineOut (f, 'Name: ', name);
  888.               LineOut (f, 'Reply-To: ', replyTo);
  889.               LineOut (f, 'Wg. : ', Betreff);
  890.               IF Empfaenger # NIL
  891.               THEN
  892.                 MagicStrings.Assign (Empfaenger^, tmpLine);
  893.                 IF (Gruppe = dataSys.private) & 
  894.                     EigeneNachricht
  895.                 THEN
  896.                   MagicStrings.Append(' (', tmpLine);
  897.                   MagicStrings.Append(Datum, tmpLine);
  898.                   MagicStrings.Append(')', tmpLine);
  899.                 END;
  900.                 LineOut (f, 'An  : ', ADR(tmpLine));
  901.               END;
  902.               (* Jetzt noch den Usenet-Krempel *)
  903.               LineOut (f, 'Box : ', box);
  904.               LineOut (f, 'MId : ', mid);
  905.               LineOut (f, 'RId : ', rid);
  906.               LineOut (f, 'Gate: ', gate);
  907.               LineOut (f, 'MIME: ', mime);
  908.               mtTextfiles.WriteLn (f);
  909.             END;
  910.  
  911.             (* Und jetzt k”nnen wir den Text ausgeben *)
  912.             messageOut (f, mess, '');
  913.             
  914.             IF ~dataMode
  915.             THEN
  916.               (* Jetzt noch ein paar Trennzeilen *)
  917.               FOR i := 0 TO emptyLines-1 DO 
  918.                 mtTextfiles.WriteLn (f);
  919.               END;
  920.             END;
  921.             
  922.             (* Speicher freigeben *)
  923.             DEALLOCATE (Text, 0);
  924.             DEALLOCATE (InfoStrings, 0);
  925.           END; (* WITH mess DO *)
  926.         END; (* IF data.error *)
  927.         (* N„chste selektierte finden *)
  928.         INC (idx);
  929.         WHILE (idx <= maxPos) & ~(Selected IN list^[idx].flags) DO INC (idx) END;
  930.         IF idx <= maxPos
  931.         THEN
  932.           msgNum := list^[idx].msgNum;
  933.         ELSE
  934.           msgNum := dataSys.empty;
  935.         END;
  936.       END; (* WHILE *)
  937.     END; (* IF hasSelectedEntries *)
  938.   END; (* WITH ptr^ DO *)
  939. END listSaveText;
  940.  
  941. PROCEDURE listDecode (ptr: listWdwPtr);
  942.   VAR firstSel  : CARDINAL;
  943.       msgNum    : CARDINAL;
  944.       idx       : CARDINAL;
  945.       mess      : data.MessageType;
  946.       i         : INTEGER;
  947.       textIdx   : CARDINAL;
  948.       line,
  949.       text      : POINTER TO ARRAY [0..32767] OF CHAR;
  950.       chPtr     : POINTER TO CHAR;
  951.       saveCh    : CHAR;
  952. BEGIN
  953.   WITH ptr^ DO
  954.     IF hasSelectedEntries (ptr, firstSel)
  955.     THEN
  956.       msgNum := list^[firstSel].msgNum;
  957.       idx := firstSel;
  958.       CatGlobal.busyMouse();
  959.       UUDecode.BeginDecode ();
  960.       WHILE msgNum < dataSys.notSaved DO
  961.         (* Message lesen *)
  962.         CatGlobal.busyMouse();
  963.         data.ReadMessage (grHandle^.Zugriff, msgNum, mess);
  964.         IF data.error = data.noError
  965.         THEN
  966.           WITH mess DO
  967.             textIdx := 0;
  968.             chPtr := ADDRESS(Text);
  969.             REPEAT
  970.               (* Startadresse festlegen *)
  971.               text := ADDRESS(chPtr);
  972.               (* Zeilenende suchen *)
  973.               WHILE (chPtr^ # CR) & (chPtr^ # LF) & (textIdx < textLen) DO
  974.                 INC (textIdx);
  975.                 INC (chPtr);
  976.               END;
  977.               saveCh := chPtr^;
  978.               chPtr^ := 0C;
  979.               IF ~UUDecode.DecodeLine (text^)
  980.               THEN
  981.                 MTE.info ("[3][CAT:|Beim Decodieren des Textes ist|ein Fehler aufgetreten!][:[Abbruch]");
  982.                 DEALLOCATE (Text, 0);
  983.                 DEALLOCATE (InfoStrings, 0);
  984.                 UUDecode.EndDecode ();
  985.                 mtAppl.MouseArrow();
  986.                 RETURN 
  987.               END;
  988.               chPtr^ := saveCh;
  989.               INC (textIdx);
  990.               INC (chPtr);
  991.               (* N„chsten Zeilenanfang finden *)
  992.               WHILE (chPtr^ = CR) & (chPtr^ = LF) & (textIdx < textLen) & (chPtr^ # saveCh) DO
  993.                 INC (textIdx);
  994.               END;
  995.             UNTIL (textIdx >= textLen);
  996.             (* Speicher freigeben *)
  997.             DEALLOCATE (Text, 0);
  998.             DEALLOCATE (InfoStrings, 0);
  999.           END; (* WITH mess DO *)
  1000.         END; (* IF data.error *)
  1001.       
  1002.         (* N„chste selektierte finden *)
  1003.         INC (idx);
  1004.         WHILE (idx <= maxPos) & ~(Selected IN list^[idx].flags) DO INC (idx) END;
  1005.         IF idx <= maxPos
  1006.         THEN
  1007.           msgNum := list^[idx].msgNum;
  1008.         ELSE
  1009.           msgNum := dataSys.empty;
  1010.         END;
  1011.       END; (* WHILE *)
  1012.       UUDecode.EndDecode ();
  1013.       mtAppl.MouseArrow();
  1014.     END; (* IF hasSelectedEntries *)
  1015.   END; (* WITH ptr^ DO *)
  1016. END listDecode;
  1017.  
  1018. PROCEDURE listSave (ptr : listWdwPtr; REF path, name : ARRAY OF CHAR; 
  1019.                     saveMode : INTEGER; askOverwrite: BOOLEAN; append: BOOLEAN);
  1020.   VAR fname : CatTypes.String255;
  1021.       fileOpenMode: mtTextfiles.Textmode;
  1022.       exists    : BOOLEAN;
  1023.       out       : mtTextfiles.TEXTFILE;
  1024.       isOutfile : BOOLEAN;
  1025.       tmp       : ARRAY [0..3] OF CHAR;
  1026.       fPos      : LONGCARD;
  1027.       i         : INTEGER;
  1028. BEGIN
  1029.   WITH ptr^ DO
  1030.     (* Dateinamen basteln *)
  1031.     MagicStrings.Assign (path, fname);
  1032.     MagicStrings.Append (name, fname);
  1033.     (* Erstmal feststellen, ob die Datei existiert *)
  1034.     fPos := CatFiles.FileSize (fname, exists);
  1035.     fileOpenMode := mtTextfiles.WRITE;
  1036.     IF exists 
  1037.     THEN
  1038.       IF askOverwrite
  1039.       THEN
  1040.         v.int := mtAlerts.Alert (2,MTE.Overwrite);
  1041.         IF v.int = 3 THEN 
  1042.           RETURN 
  1043.         ELSIF v.int = 2
  1044.         THEN
  1045.           fileOpenMode := mtTextfiles.APPEND;
  1046.         ELSE
  1047.           fileOpenMode := mtTextfiles.WRITE;
  1048.         END;
  1049.       ELSE
  1050.         IF append 
  1051.         THEN
  1052.           fileOpenMode := mtTextfiles.APPEND;
  1053.         ELSE
  1054.           fileOpenMode := mtTextfiles.WRITE;
  1055.         END;
  1056.       END;
  1057.     END;
  1058.     isOutfile := FALSE;
  1059.     IF fileOpenMode = mtTextfiles.APPEND
  1060.     THEN
  1061.       (* Erstmal kurz die letzten drei Byte lesen *)
  1062.       IF mtTextfiles.OpenTextfile (fname, mtTextfiles.READ, 32768, out)
  1063.       THEN
  1064.         (* In fPos steht schon die Gr”že *)
  1065.         IF (fPos >= 3)
  1066.         THEN
  1067.           mtTextfiles.SetTextpos (out, fPos-3);
  1068.           FOR i := 0 TO 2 DO
  1069.             mtTextfiles.ReadChar (out, tmp[i]);
  1070.           END;
  1071.           tmp[3] := 0C;
  1072.           (* Jetzt Test auf #CRLF *)
  1073.           IF MagicStrings.Equal (tmp, "#"+CR+LF)
  1074.           THEN
  1075.             isOutfile := TRUE;
  1076.           END;
  1077.         END;
  1078.         mtTextfiles.CloseTextfile (out);
  1079.       END;
  1080.     END;
  1081.  
  1082.     (* So, jetzt die Datei ”ffnen *)
  1083.     IF mtTextfiles.OpenTextfile (fname, fileOpenMode, 32768, out)
  1084.     THEN
  1085.       mtAppl.MouseBusy();
  1086.       CASE saveMode OF
  1087.         smListe :   listSaveList (ptr, out); |
  1088.         smOutfile:  listSaveOutfile (ptr, out, isOutfile); |
  1089.         smText  :   listSaveText (ptr, out, FALSE); |
  1090.         (*
  1091.         smData  :   listSaveText (ptr, out, TRUE); |
  1092.         *)
  1093.         smStatus:   listSaveStatus (ptr, out); |
  1094.       ELSE
  1095.       END;
  1096.       mtTextfiles.CloseTextfile(out);
  1097.       mtAppl.MouseArrow();
  1098.     ELSE
  1099.       MTE.info (MTE.NoWrite);
  1100.     END;
  1101.   END;
  1102. END listSave;
  1103.  
  1104. PROCEDURE listSaveAs (wdw: INTEGER);
  1105. (* Speichert die selektierten Nachrichten in einer Datei *)
  1106.   VAR p : listWdwPtr;
  1107.       saveMode : INTEGER;
  1108.       kstate   : BITSET;
  1109. BEGIN
  1110.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  1111.     IF hasSelectedEntries (p, v.card)
  1112.     THEN
  1113.       saveMode := mtAlerts.Alert (lastSaveMode, MTE.listMode);
  1114.       MagicAES.GrafMkstate (v.int, v.int, v.bset, kstate);
  1115.       IF saveMode = 5 THEN RETURN END;
  1116.       lastSaveMode := saveMode;
  1117.       IF (saveMode = 1) & (CatGlobal.WithCtrl (kstate))
  1118.       THEN 
  1119.         v.int := mtAlerts.Alert (2, "[2][CAT:|Liste als Statusmeldungen sichern?][[Abbruch|[OK]");
  1120.         IF v.int = 2
  1121.         THEN 
  1122.           saveMode := 6;
  1123.         END;
  1124.       END;
  1125.       IF saveMode = 4
  1126.       THEN
  1127.         listDecode (p);
  1128.       ELSE
  1129.         (* Jetzt Datei ausw„hlen *)
  1130.         IF CatGlobal.FselGet (CatGlobal.SavePath, CatGlobal.SaveName, '*.txt', 'Nachrichten speichern als...', FALSE)
  1131.         THEN
  1132.           (* Ok, Name ist ausgew„hlt *)
  1133.           listSave (p, CatGlobal.SavePath, CatGlobal.SaveName, saveMode, TRUE, FALSE);
  1134.           Protokoll.SendPathUpdate (CatGlobal.SavePath);
  1135.         END;
  1136.       END;
  1137.     END;
  1138.   END;
  1139. END listSaveAs;
  1140.  
  1141. CONST
  1142.         ScrapName = 'SCRAP.TXT';
  1143.  
  1144. PROCEDURE listCopy(wdw : INTEGER);
  1145. (* Alle selektierten Nachrichten werden exportiert*)
  1146.   VAR p : listWdwPtr;
  1147.       append    : BOOLEAN;
  1148.       state     : BITSET;
  1149.       path      : CatTypes.String255;
  1150.       saveMode  : INTEGER;
  1151. BEGIN
  1152.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  1153.     IF hasSelectedEntries (p, v.card)
  1154.     THEN
  1155.       MagicAES.GrafMkstate(v.int, v.int, v.bset, state);
  1156.       append := CatGlobal.WithShift (state);
  1157.       IF Clip.GetScrap (path)
  1158.       THEN
  1159.         saveMode := mtAlerts.Alert (lastSaveMode, MTE.listMode);
  1160.         IF saveMode = 5 THEN RETURN END;
  1161.         (*
  1162.         IF (saveMode = smOutfile) & (p^.grHandle^.group = dataSys.private)
  1163.         THEN
  1164.           v.int := mtAlerts.Alert (2, MTE.expPrivate);
  1165.           IF v.int = 1 THEN RETURN END;
  1166.         END;
  1167.         *)
  1168.         lastSaveMode := saveMode;
  1169.         IF append
  1170.         THEN
  1171.           Clip.ScrapClear ("", ScrapName);
  1172.         ELSE
  1173.           Clip.ScrapClear ("", "");
  1174.         END;
  1175.         IF saveMode = 4 
  1176.         THEN
  1177.           listDecode (p);
  1178.         ELSE
  1179.           listSave (p, path, ScrapName, saveMode, FALSE, append);
  1180.         END;
  1181.       END;
  1182.     END;
  1183.   END;
  1184. END listCopy;
  1185.  
  1186. PROCEDURE listSomethingSelected (wdw: INTEGER): BOOLEAN;
  1187. (* Gibt zurck, ob in der Stichwortliste Nachrichten markiert 
  1188.  * sind
  1189.  *)
  1190.   VAR p : listWdwPtr;
  1191. BEGIN
  1192.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  1193.     RETURN hasSelectedEntries (p, v.card);
  1194.   END;
  1195.   RETURN FALSE;
  1196. END listSomethingSelected; 
  1197.  
  1198. PROCEDURE listSetFlags(wdw : INTEGER; setBits, clearBits : BITSET);
  1199. (* Fr alle selektierten Nachrichten 
  1200.  * ein paar Flags setzen oder l”schen 
  1201.  *)
  1202.   VAR p : listWdwPtr;
  1203.       bits,
  1204.       newBits : BITSET;
  1205.       (*$Reg*) counter : CARDINAL;
  1206.       (*$Reg*) i       : CARDINAL;
  1207. BEGIN
  1208.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, p) THEN
  1209.     WITH p^ DO
  1210.       CatGlobal.busyMouse();
  1211.       counter := 0;
  1212.       FOR i := 0 TO maxPos DO
  1213.         IF Selected IN list^[i].flags THEN 
  1214.           data.ReadState (grHandle^.Zugriff, list^[i].msgNum, bits);
  1215.           IF data.error = data.noError
  1216.           THEN
  1217.             (* Neue Flags berechnen *)
  1218.             newBits := (bits-clearBits)+setBits;
  1219.             (* Flags setzen *)
  1220.             data.SetBits(grHandle^.Zugriff, list^[i].msgNum, newBits);
  1221.             INC (counter);
  1222.             IF counter MOD 50 = 0 THEN CatGlobal.busyMouse(); END;
  1223.           END;
  1224.         END;
  1225.       END;
  1226.       mtAppl.MouseArrow();
  1227.     END;
  1228.     (* Und jetzt vorsichtshalber Redraw ausl”sen *)
  1229.     WdwManager.FullRedrawWdw (wdw);
  1230.   END;
  1231. END listSetFlags;
  1232.  
  1233. PROCEDURE listSavePos();
  1234.   VAR lauf : listWdwPtr;
  1235.       varName : ARRAY [0..255] OF CHAR;
  1236.       full    : GrafBase.Rectangle;
  1237. BEGIN
  1238.   Lists.ResetList(windows);
  1239.   lauf := Lists.NextEntry(windows);
  1240.   WHILE lauf # NIL DO
  1241.     WITH lauf^ DO
  1242.       IF wdw > 0
  1243.       THEN
  1244.         Strings.Concat (cListGroup, StrConv.IntToStr (number, 0), varName, v.bool);
  1245.         v.bool := ConfVars.SetConfigLongInt (varName, VAL(LONGINT, grHandle^.group));
  1246.         Strings.Concat (cListStart, StrConv.IntToStr (number, 0), varName, v.bool);
  1247.         v.bool := ConfVars.SetConfigLongInt (varName, VAL(LONGINT, startPos));
  1248.   
  1249.         Strings.Concat (cListWdw, StrConv.IntToStr (number, 0), varName, v.bool);
  1250.         WdwManager.GetWdwSize (wdw, full); (* Gr”že des Fensters abfragen *)
  1251.         v.bool := ConfVars.SetConfigRect (varName, full);
  1252.         Strings.Concat (cListFont, StrConv.IntToStr (number, 0), varName, v.bool);
  1253.         v.bool := ConfVars.SetConfigInt (varName, font);
  1254.         Strings.Concat (cListSize, StrConv.IntToStr (number, 0), varName, v.bool);
  1255.         v.bool := ConfVars.SetConfigInt (varName, fontSize);
  1256.       END;
  1257.     END;
  1258.     lauf := Lists.NextEntry(windows);
  1259.   END;
  1260. END listSavePos;
  1261.  
  1262. PROCEDURE listRestorePos();
  1263. VAR varName : ARRAY [0..255] OF CHAR;
  1264.     number  : INTEGER;
  1265.     gruppe, 
  1266.     mailNr  : CARDINAL;
  1267. BEGIN
  1268.   FOR number := 0 TO 255 DO 
  1269.     Strings.Concat (cListGroup, StrConv.IntToStr (number, 0), varName, v.bool);
  1270.     IF ConfVars.GetConfigLongInt (varName, v.lint) 
  1271.     THEN
  1272.       gruppe := VAL (CARDINAL, v.lint);
  1273.       Strings.Concat (cListStart, StrConv.IntToStr (number, 0), varName, v.bool);
  1274.       IF ConfVars.GetConfigLongInt (varName, v.lint)
  1275.       THEN
  1276.         mailNr := VAL (CARDINAL, v.lint);
  1277.         globalNumber := number;
  1278.         listOpen (gruppe, mailNr, -1, grin.mOther);
  1279.       END;
  1280.     END;
  1281.   END;
  1282.   globalNumber := -1;
  1283. END listRestorePos;
  1284.  
  1285. PROCEDURE listCloseAll ();
  1286. (* Alle Sichwortlistenfenster werden geschlossen *)
  1287.   VAR lauf : listWdwPtr;
  1288. BEGIN
  1289.   Lists.ResetList(windows);
  1290.   lauf := Lists.NextEntry(windows);
  1291.   WHILE lauf # NIL DO
  1292.     listClose(lauf^.wdw);
  1293.     lauf := Lists.NextEntry(windows);
  1294.   END;
  1295. END listCloseAll;
  1296.  
  1297. PROCEDURE listFreeAll();
  1298. (* Schliežt alle Stichwortlistenfenster und gibt auch alle Handles wieder 
  1299.  * frei 
  1300.  *)
  1301.   VAR lauf : listWdwPtr;
  1302. BEGIN
  1303.   listCloseAll();
  1304.   Lists.ResetList (windows);
  1305.   lauf := Lists.NextEntry (windows);
  1306.   WHILE lauf # NIL DO
  1307.     IF lauf^.usedByGrin > 0
  1308.     THEN
  1309.       freeList (lauf);
  1310.       handlePool.FreeOneDataHandle(lauf^.grHandle);
  1311.       handlePool.FreeOnePtr(lauf, windows);
  1312.       Lists.ResetList (windows);
  1313.     END;
  1314.     lauf := Lists.NextEntry (windows);
  1315.   END;
  1316. END listFreeAll;
  1317.  
  1318. PROCEDURE listWindowTop (wdw : INTEGER) : BOOLEAN;
  1319. (* Ist ein Stichwortlistenfenster oben? *)
  1320. BEGIN
  1321.   RETURN handlePool.FindEntry(ADR(wdw), FindWinCond, windows, v.a);
  1322. END listWindowTop;
  1323.  
  1324. PROCEDURE listSetFont (wdw: INTEGER; font, fontSize : INTEGER);
  1325. BEGIN
  1326.   iListSetFont (wdw, font, fontSize, TRUE);
  1327. END listSetFont;
  1328.  
  1329. PROCEDURE listCloseByHandle (hdl : LONGCARD);
  1330. (* Ein Stichwortlistenfenster wird ber das assoziierte Handle 
  1331.  * geschlossen, wird von grin aufgerufen, wenn ein Fenster mit
  1332.  * geschlossen wird, an das eine Stichwortliste gelinkt ist
  1333.  *)
  1334.   VAR ptr : listWdwPtr;
  1335. BEGIN
  1336.   IF handlePool.FindEntry(ADR(hdl), FindHandleCond, windows, ptr) 
  1337.   THEN
  1338.     IF (ptr^.wdw >= 0)
  1339.     THEN
  1340.       v.bool := WdwManager.CloseWindow (ptr^.wdw, TRUE);
  1341.     END;
  1342.   END;
  1343. END listCloseByHandle;
  1344.  
  1345. PROCEDURE listUnlockWdw (hdl : LONGCARD);
  1346.   VAR ptr : listWdwPtr;
  1347. BEGIN
  1348.   IF handlePool.FindEntry(ADR(hdl), FindHandleCond, windows, ptr) 
  1349.   THEN
  1350.     IF ptr^.usedByGrin > 0 
  1351.     THEN 
  1352.       DEC (ptr^.usedByGrin);
  1353.     END;
  1354.     IF ptr^.wdw >= 0
  1355.     THEN 
  1356.       RETURN 
  1357.     ELSIF ptr^.usedByGrin = 0
  1358.     THEN
  1359.       freeList (ptr);
  1360.       handlePool.FreeOneDataHandle(ptr^.grHandle);
  1361.       handlePool.FreeOnePtr(ptr, windows);
  1362.     END;
  1363.   END;
  1364. END listUnlockWdw;
  1365.  
  1366. PROCEDURE listChangeGroup (hdl: LONGCARD; grinWdw: INTEGER; mess, newGroup: CARDINAL; 
  1367.                            mode: grin.openMode): BOOLEAN;
  1368.   VAR newPtr, ptr : listWdwPtr;
  1369.   
  1370.   PROCEDURE openGroup (gruppe, which: CARDINAL; VAR ptr: listWdwPtr): BOOLEAN;
  1371.   (* Ein Stichwortliste intern aufbauen ohne Fenster *)
  1372.   VAR handlePtr : handlePool.oneHandlePtr;
  1373.       i         : CARDINAL;
  1374.       varname   : ARRAY [0..127] OF CHAR;
  1375.       doRedraw  : BOOLEAN;
  1376.   BEGIN
  1377.     (* Gruppe ”ffnen und Stichwortliste anzeigen *)
  1378.     IF handlePool.BlankToList(ptr, TSIZE(listWindow), windows) THEN
  1379.       IF handlePool.GetOneDatahandle(gruppe, handlePtr) THEN
  1380.         ptr^.wdw := -1;
  1381.         ptr^.grHandle := handlePtr;
  1382.         ptr^.grinWindow := -1;
  1383.         MakeTitle (gruppe, ptr^.grName);
  1384.         ptr^.maxPos   := data.LastMsgOfGroup (gruppe);
  1385.         IF ptr^.maxPos = dataSys.empty
  1386.         THEN
  1387.           handlePool.FreeOneDataHandle(handlePtr);
  1388.           handlePool.FreeOnePtr (ptr, windows);
  1389.           RETURN FALSE
  1390.         END;
  1391.         IF which > ptr^.maxPos THEN which := ptr^.maxPos END;
  1392.         ptr^.usedByGrin := 0;
  1393.         (* Jetzt "Liste" aufbauen *)
  1394.         ALLOCATE (ptr^.wholeList, LONG(ptr^.maxPos + 1) * LONG(TSIZE (listEntry)));
  1395.         IF ptr^.wholeList # NIL THEN
  1396.           ptr^.list := ptr^.wholeList;
  1397.           (* Liste fllen *)
  1398.           FOR i := 0 TO ptr^.maxPos DO
  1399.             ptr^.wholeList^[i] := listEntry(lEntry{i, {}, NIL});
  1400.           END;
  1401.           IF gruppe = dataSys.private
  1402.           THEN
  1403.             ptr^.partArray := privateParts;
  1404.           ELSE
  1405.             ptr^.partArray := globalParts;
  1406.           END;
  1407.           ptr^.startPos := which;
  1408.           ptr^.maxWidth := 0;
  1409.           ptr^.isLocked := FALSE;
  1410.           doRedraw := FALSE;
  1411.           ptr^.unreadOrNew := (mode=grin.mFirstNew) OR (mode=grin.mUnread);
  1412.           ptr^.openMode := mode;
  1413.           (* Jetzt eventuell verkleinern *)
  1414.           IF ptr^.unreadOrNew
  1415.           THEN
  1416.             ConfVars.GetConfDefBool (cListShrink, v.bool, FALSE);
  1417.             IF v.bool
  1418.             THEN
  1419.               (* Liste verkleinern *)
  1420.               shrinkToEnd (ptr, FALSE);
  1421.               (* doRedraw := TRUE; *)
  1422.             END;
  1423.             (* Jetzt eventuell gefilterte rausnehmen *)
  1424.             ConfVars.GetConfDefBool (cListFilter, v.bool, FALSE);
  1425.             IF v.bool
  1426.             THEN
  1427.               (* Gefilterte selektieren und dann Liste verkleinern *)
  1428.               listSelectFiltered (ptr^.wdw, TRUE, FALSE);
  1429.               v.bool := shrinkList (ptr, TRUE, FALSE);
  1430.               (* doRedraw := TRUE; *)
  1431.             END;
  1432.             (* Eventuellen Autoselect durchfhren *)
  1433.             FOR i := 1 TO 10 DO
  1434.               MagicStrings.Assign (cListSearch, varname);
  1435.               MagicStrings.Append (StrConv.CardToStr (i, 0), varname);
  1436.               ConfVars.GetConfDefBool (varname, v.bool, FALSE);
  1437.               IF v.bool
  1438.               THEN
  1439.                 (* Ok, steht auf TRUE, also selektieren *)
  1440.                 ptr^.isLocked := TRUE;
  1441.                 IF SearchHelp.getKonf (i-1, SearchHelp.suchVar)
  1442.                  & SearchHelp.ValidateKonf (SearchHelp.suchVar)
  1443.                 THEN
  1444.                   doMark (ptr, FALSE);
  1445.                   doRedraw := TRUE;
  1446.                 END;
  1447.                 ptr^.isLocked := FALSE;
  1448.               END;
  1449.             END;
  1450.             (* Jetzt mal nachsehen, ob wir auch sortieren mssen *)
  1451.             ConfVars.GetConfDefInt (cListSort, v.int, 3);
  1452.             IF sortType(v.int) # sNum
  1453.             THEN
  1454.               ptr^.isLocked := TRUE;
  1455.               doSort (ptr, sortType(v.int), FALSE);
  1456.               doRedraw := TRUE;
  1457.               ptr^.isLocked := FALSE;
  1458.             END;
  1459.           END;
  1460.           IF doRedraw
  1461.           THEN
  1462.             WdwManager.FullRedrawWdw (ptr^.wdw);
  1463.           END;
  1464.         ELSE
  1465.           handlePool.FreeOneDataHandle(handlePtr);
  1466.           handlePool.FreeOnePtr (ptr, windows);
  1467.           MTE.noMemAlert();
  1468.           RETURN FALSE;
  1469.         END;
  1470.       ELSE
  1471.         handlePool.FreeOnePtr (ptr, windows);
  1472.         MTE.noMemAlert();
  1473.         RETURN FALSE;
  1474.       END;
  1475.     ELSE
  1476.       MTE.noMemAlert();
  1477.       RETURN FALSE
  1478.     END;
  1479.     RETURN TRUE;
  1480.   END openGroup;
  1481.   
  1482. BEGIN
  1483.   IF handlePool.FindEntry(ADR(hdl), FindHandleCond, windows, ptr) 
  1484.   THEN
  1485.     IF grinWdw # ptr^.grinWindow
  1486.     THEN
  1487.       RETURN FALSE;
  1488.     END;
  1489.     IF (ptr^.wdw >= 0) & openGroup (newGroup, mess, newPtr)
  1490.     THEN
  1491.       listUnlockWdw (hdl);
  1492.       IF ptr^.usedByGrin = 0
  1493.       THEN
  1494.         WITH ptr^ DO
  1495.           (* Speicher freigeben und Gruppe schliežen *)
  1496.           freeList (ptr);
  1497.           handlePool.FreeOneDataHandle(grHandle);
  1498.           (* Jetzt neue Variablen berkopieren *)
  1499.           wholeList:= newPtr^.wholeList;
  1500.           list     := newPtr^.list;
  1501.           grHandle := newPtr^.grHandle;
  1502.           grName   := newPtr^.grName;
  1503.           maxPos   := newPtr^.maxPos;
  1504.           startPos := newPtr^.startPos;
  1505.           maxWidth := newPtr^.maxWidth;
  1506.           partArray:= newPtr^.partArray;
  1507.           (* neuen Ptr wieder freigeben *)
  1508.           handlePool.FreeOnePtr (newPtr, windows);
  1509.           newPtr := ptr;
  1510.         END;
  1511.       ELSE
  1512.         (* Alte Gruppe ist mehrfach belegt, geht nicht. Neue wieder schliežen und
  1513.          * alles freigeben
  1514.          *)
  1515.         freeList (newPtr);
  1516.         handlePool.FreeOneDataHandle(newPtr^.grHandle);
  1517.         handlePool.FreeOnePtr(newPtr, windows);
  1518.         RETURN FALSE
  1519.       END;
  1520.       (* Nun auch dem Windowmanager ber die neuen Sachen informieren *)
  1521.       WITH newPtr^ DO
  1522.         (* grinWdw setzen *)
  1523.         grinWindow := grinWdw;
  1524.         (* Titel umsetzen *)
  1525.         WdwManager.SetWdwTitle (wdw, grName);
  1526.         (* Neue Dokumentparameter setzen *)
  1527.         leftOffset := 0;
  1528.         WdwManager.SetNewDocument (wdw, GrafBase.LongRect{LONG(leftOffset), startPos, LONG(maxWidth), maxPos}, TRUE);
  1529.       END;
  1530.       (* Und jetzt noch grin Bescheid sagen, daž es ein neues Fenster gibt. 
  1531.        * Wichtig wegen der NextMessProzedur
  1532.        *)
  1533.       v.bool := grin.grinSetListWdw (newPtr^.grinWindow, grin.grinNextMess, LONGCARD (newPtr));
  1534.       RETURN TRUE;
  1535.     ELSE
  1536.       listUnlockWdw (hdl);  (* muž gemacht werden *)
  1537.       RETURN FALSE (* Gruppe konnte nicht ge”ffnet werden *)
  1538.     END;
  1539.   ELSE
  1540.     RETURN FALSE;
  1541.   END;
  1542. END listChangeGroup;
  1543.  
  1544. PROCEDURE listSearch (wdw: INTEGER);
  1545. (* Nachrichten werden ber die Suchfunktion markiert 
  1546.  *)
  1547.   VAR ptr: listWdwPtr;
  1548. BEGIN
  1549.   IF handlePool.FindEntry(ADR(wdw), FindWinCond, windows, ptr) 
  1550.   THEN
  1551.     doMark (ptr, TRUE);
  1552.   END;
  1553. END listSearch;
  1554.  
  1555. PROCEDURE parseListLine (REF listline : ARRAY OF CHAR; private : BOOLEAN; onlyTest : BOOLEAN) : BOOLEAN; 
  1556. TYPE charSet = SET OF CHAR;
  1557. CONST okSet = charSet{'A','C', 'D', 'E', 'F', 'H', 'I', 'L', 'M', 'R' , 'S', 'U', 'W', '#', ',', ' '};
  1558.      numSet = charSet{'0'..'9'};
  1559.      skipSet = charSet{' ',','};
  1560.      formatSet = charSet{'B','D','H','T'};
  1561.   VAR p : partArrayDesc;
  1562.       num : LONGCARD;
  1563.       ch  : CHAR;
  1564.       z, l: CARDINAL;
  1565.       pName : partNameType;
  1566.       fStr  : partFormat;
  1567.       i     : INTEGER;
  1568. BEGIN 
  1569.   l := LENGTH (listline);
  1570.   IF l = 0 THEN RETURN FALSE END;
  1571.   z := 0;
  1572.   p.lines := 0;
  1573.   p.width := 0;
  1574.   WHILE z < l DO
  1575.     (* Ersten Eintrag suchen *)
  1576.     WHILE (z < l) & (listline[z] IN skipSet) DO INC (z) END;
  1577.     IF z < l
  1578.     THEN
  1579.       ch := listline[z];
  1580.       FOR i := 0 TO partFormatLength-1 DO fStr[i] := 0C; END;
  1581.       IF (listline[z+1] # '(') THEN RETURN FALSE END;
  1582.       INC (z,2);        (* z+1 = '(' *)
  1583.       num := 0;
  1584.       WHILE (listline [z] IN numSet) & (z < l) DO num := num * 10 + LONG(ORD (listline[z]) - ORD('0')); INC(z); END;
  1585.       IF (z >= l) OR 
  1586.          ( (listline[z] # ')') &
  1587.            ( (listline[z] # ',') & ~(ch IN formatSet))
  1588.          )
  1589.       THEN 
  1590.         RETURN FALSE 
  1591.       END;
  1592.       IF (listline[z] = ',') & (ch IN formatSet)
  1593.       THEN
  1594.         (* Formatstring lesen *)
  1595.         INC (z);    (* ',' berspringen *)
  1596.         i := 0;
  1597.         WHILE (listline[z] # ')') & (z < l) & (i < partFormatLength) DO
  1598.           fStr[i] := listline[z];
  1599.           INC (z); INC (i);
  1600.         END;
  1601.         IF (i >= partFormatLength) OR (z >= l) THEN RETURN FALSE END; 
  1602.       END;
  1603.       INC(z);   (* ')' berspringen *)
  1604.       CASE ch OF
  1605.         'A' : pName := pRealName |
  1606.         'B' : pName := pWeekday;
  1607.               IF fStr[0] = ''
  1608.               THEN
  1609.                 Strings.Assign ('GGGGGGGGGGG', fStr, v.bool);
  1610.               ELSIF (fStr[0] = '#') & (fStr[1] # '')
  1611.               THEN
  1612.                 ch := fStr[1];
  1613.                 FOR i := 0 TO partFormatLength DO
  1614.                   fStr[i] := ch;
  1615.                 END;
  1616.               END;  |
  1617.         'C' : pName := pComments |
  1618.         'D' : pName := pDatum;
  1619.               IF fStr[0] = ''
  1620.               THEN
  1621.                 Strings.Assign ('DD.MM.YY', fStr, v.bool);
  1622.               END;    |
  1623.         'E' : pName := pOwnMess  |
  1624.         'F' : pName := pFlags    |
  1625.         'H' : pName := pFuzzytime;
  1626.               IF fStr[0] = ''
  1627.               THEN
  1628.                 Strings.Assign ('G', fStr, v.bool);
  1629.               END; |
  1630.         'L' : pName := pLength   |
  1631.         'M' : pName := pMailId   |
  1632.         'I' : pName := pMId      |
  1633.         'R' : pName := pRefId    |
  1634.         'S' : pName := pStatus   |
  1635.         'T' : pName := pTime;
  1636.               IF fStr[0] = ''
  1637.               THEN
  1638.                 Strings.Assign ('HH:MM', fStr, v.bool);
  1639.               END;    |
  1640.         'U' : pName := pUserName |
  1641.         'W' : pName := pWegen    |
  1642.         '#' : pName := pCount    |
  1643.       ELSE
  1644.         RETURN FALSE;
  1645.       END;
  1646.       IF (num = 0) OR (num > 1024) THEN RETURN FALSE END;
  1647.       p.parts[p.lines] := partType{pName, INTEGER(SHORT(num)), fStr}; 
  1648.       INC (p.lines);
  1649.       INC (p.width, num);
  1650.     END;
  1651.   END;
  1652.   IF p.lines = 0
  1653.   THEN 
  1654.     RETURN FALSE 
  1655.   END;
  1656.   IF onlyTest THEN RETURN TRUE END;
  1657.   IF private
  1658.   THEN
  1659.     v.bool := ConfVars.SetConfigString (cPrivateLine, listline);
  1660.     privateParts := p;
  1661.   ELSE
  1662.     v.bool := ConfVars.SetConfigString (cGlobalLine, listline);
  1663.     globalParts := p;
  1664.   END;
  1665.   RETURN TRUE;
  1666. END parseListLine;
  1667.  
  1668. PROCEDURE CheckListLine (REF listline : ARRAY OF CHAR): BOOLEAN; 
  1669. (* Testet, ob die bergebene Zeile fr die Stichwortliste in Ordnung ist *)
  1670.  
  1671.   (* Das Format einer Zeile besteht aus einzelnen Krzeln 
  1672.    * fr einen Eintrag und darauffolgend in Klammern die Weite dieses Eintrages.
  1673.    * Beispiel: D(12),I(10),U(30),W(30),F(2)
  1674.    * Erlaubte Zeilenelemente:
  1675.    * D: Datum. Das Datum ist maximal 12 Zeichen lang und hat folgende Form:
  1676.    *           Mo, 16.11.92
  1677.    *    Optional kann man auch einen Formatstring angeben, der folgende Elemente
  1678.    *    enthalten darf:
  1679.    *     D: Tagesziffer  (d: wird gel”scht, wenn nicht auffllbar)
  1680.    *     Y: Jahresziffer (y: wird gel”scht, wenn nicht auffllbar)
  1681.    *     M: Monatsziffer (m: wird gel”scht, wenn nicht auffllbar)
  1682.    *     G: Monatsbuchstabe Deutsch
  1683.    *     F: Monatsbuchstabe Fr„nz”sisch
  1684.    *     E: Monatsbuchstabe English
  1685.    *     #E (Hinter Ziffern): englische Zahlfortsetzung (1st, 2nd, 3rd, 4th...)
  1686.    * T: Zeit. Default-Format fr die Zeit ist HH:SS, also 06:13.
  1687.    *    Optional kann man auch einen Formatstring angeben, der folgendes 
  1688.    *    enthalten darf:
  1689.    *
  1690.    *   HH: Stundenzahl ("hh" l”scht fhrende Null)
  1691.    *   MM: Minutenzahl ("mm" l”scht fhrende Null)
  1692.    *   SS: Sekundenzahl ("ss" l”scht fhrende Null) 
  1693.    *
  1694.    *   #E: AM/PM-Notierung (English) ("e" schreibt "am" bzw. "pm")
  1695.    *
  1696.    *   Beispiel: Aus 'hh Uhr mm' wird '13 Uhr 5'
  1697.    *   Die Angabe von Sekunden in einem Formatstring ist allerdings unsinnig,
  1698.    *   da die Zeitangaben zu Mails keine Sekunden enthalten.
  1699.    * W: Wochentag. Auch hier kann man einen Formatstring angeben, der die Sprache
  1700.    *    spezifiziert, in der der Wochentag ausgegeben wird.
  1701.    *
  1702.    *     G: Tagesbuchstabe Deutsch
  1703.    *     F: Tagesbuchstabe Fr„nz”sisch
  1704.    *     E: Tagesbuchstabe English
  1705.    *
  1706.    *    Es muž fr die gesamte gewnschte L„nge ein Formatbuchstabe angegeben
  1707.    *    werden.
  1708.    *    Wenn das erste Zeichen in der Maske ein # ist, dann wird die  
  1709.    *    Maske komplett mit dem zweiten Zeichen der Maske gefllt. 
  1710.    *    Beispiel: Aus #G wird intern GGGGGGGGGGGGGG
  1711.    * 
  1712.    * I: Message-Id. Im Moment ist diese maximal 10 Zeichen lang, aber ab Maus 9.0
  1713.    *                k”nnen Ids wesentlich l„nger werden.
  1714.    * R: Reference-Id: Bei Kommentaren oder Antworten die Id der Referenznachricht.
  1715.    * U: Username 
  1716.    * A: Realname (wird ersetzt durch Username, falls nicht vorhanden)
  1717.    * W: Stichwort. Vor MAUS 9 maximal 30 Zeichen.
  1718.    * F: Flags. Die Flags der Nachrichten, die man in CAT setzen kann. 
  1719.    *           Reihenfolge wie in der Messageanzeige, also LFITDKB12
  1720.    * S: Status. Nur fr pers”nliche Nachrichten, andernfalls wird es ignoriert.
  1721.    * C: Kommentare: Anzahl der Kommentare auf die Nachricht, nicht fr pers”nliche Nachrichten.
  1722.    * #: interne Nummer der Message. Maximal 5 Stellen.
  1723.    *)
  1724. BEGIN
  1725.   RETURN parseListLine (listline, FALSE, TRUE);
  1726. END CheckListLine;
  1727.  
  1728. PROCEDURE SetListLine (REF listline : ARRAY OF CHAR; private : BOOLEAN);
  1729. (* Setzt die Stichwortlistenzeile fr die private oder andere Gruppen
  1730.  * Wenn die Zeile fehlerhaft ist, wird die vorhandene Zeile nicht
  1731.  * ver„ndert.
  1732.  *)
  1733. BEGIN
  1734.   v.bool := parseListLine (listline, private, FALSE);
  1735. END SetListLine;
  1736.  
  1737. VAR init: BOOLEAN;
  1738.  
  1739. PROCEDURE InitMsgList ();
  1740. (* Initialisiert die Messageliste *)
  1741. BEGIN
  1742.   IF ~init THEN
  1743.     butBox := MausTauschrsc.TreeAddr^[MausTauschrsc.listctl];
  1744.     v.bool := mtXobjects.InstUserdef (butBox, MausTauschrsc.listread, mtDials.DrawButton, NIL);
  1745.     selPop := MausTauschrsc.TreeAddr^[MausTauschrsc.lselpop];
  1746.     removePop := MausTauschrsc.TreeAddr^[MausTauschrsc.lremvpop];
  1747.     sortPop := MausTauschrsc.TreeAddr^[MausTauschrsc.lsortpop];
  1748.   END;
  1749.   init := TRUE;
  1750. END InitMsgList;
  1751.  
  1752. BEGIN
  1753.   Lists.CreateList (windows, v.bool);
  1754.   (*
  1755.   privateParts.parts[0] := partType{pDatum, 12, ''};
  1756.   privateParts.parts[1] := partType{pMailId, 10, ''};
  1757.   privateParts.parts[2] := partType{pUserName, 30, ''};
  1758.   privateParts.parts[3] := partType{pWegen, 30, ''};
  1759.   privateParts.parts[4] := partType{pStatus, 2, ''};
  1760.   privateParts.width := 84;
  1761.   privateParts.lines := 5; 
  1762.   globalParts := privateParts;
  1763.   globalParts.parts[5] := globalParts.parts[4];
  1764.   globalParts.parts[4] := partType{pComments, 2};
  1765.   globalParts.width := 86;
  1766.   globalParts.lines := 6;
  1767.   *)
  1768.   globalNumber := -1;
  1769.   lineDist := 2;
  1770.   pixOffset := 8;
  1771.   init := FALSE;
  1772.   lastSaveMode := 1;
  1773.   extendedCommentMode := TRUE;
  1774. END msgList. 
  1775.